package cz.cuni.mff.ufal.volk;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import org.apache.log4j.Logger;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;

import cz.cuni.mff.ufal.volk.ApplicationSettings;
import cz.cuni.mff.ufal.volk.Listener;
import cz.cuni.mff.ufal.volk.Speech;
import cz.cuni.mff.ufal.volk.Text;
import cz.cuni.mff.ufal.volk.patterns.LanguageDescription;
import cz.cuni.mff.ufal.volk.patterns.Pattern;
import cz.cuni.mff.ufal.volk.services.Services;
import cz.cuni.mff.ufal.volk.services.TextToSpeech;

public class RssInputProcessor implements Listener<String> {

	private static final Logger log = Logger.getLogger(RssInputProcessor.class);

	public RssInputProcessor(NabaztagController nab, String keyword, Map<String, FeedConfiguration> addresses) {
		nab.getClass();
		keyword.getClass();
		addresses.getClass();
		this.nab = nab;
		this.keyword = keyword;
		this.registeredAddresses = new HashMap<String, FeedConfiguration>(addresses);
		this.messages = ResourceBundle.getBundle("volk/resources/messages", ApplicationSettings.getCurrent().getLocale());
//    this.messages = new Properties();
//    String resourceUrl = "/res/messages.cs.properties";
//    log.trace("trying to open properties file: " + resourceUrl);
//    URL messagesUrl = RSS.class.getResource(resourceUrl);
//    try {
//	    InputStream in = messagesUrl.openStream();
//	    if (in == null) {
//	    	log.warn("failed to open properties file");
//	    } else {
//		    try {
//		    	this.messages.load(new InputStreamReader(in));
//		    } finally {
//		    	in.close();
//		    }
//	    }
//    } catch (IOException cause) {
//    	throw new IllegalStateException("An IOException occurred when opening messages file", cause);
//    }
	}

	private final NabaztagController nab;
	private final String keyword;
	private final Map<String, FeedConfiguration> registeredAddresses;
	//private final Properties messages;
	private final ResourceBundle messages;

	private int maxMessageCount = 5;

	public int getMaxMessageCount() {
		return maxMessageCount;
	}

	public void setMaxMessageCount(int value) {
		if (value < 1)
			throw new IllegalArgumentException("Invalid maxMessages value (must be >0)");
		maxMessageCount = value;
	}

	@Override
  public void process(String event) {
	  if (event.startsWith(keyword)) {
	  	log.info("processing rss request: " + event);
	  	TextToSpeech tts = (TextToSpeech) Services.registered().get(Services.TEXT_TO_SPEECH);
	  	String[] items = event.split("\\s+");
	  	String sourceName = items.length > 1 ? items[1] : "";
	  	FeedConfiguration config = registeredAddresses.get(sourceName);
	  	if (config == null) {
	  		// unknown feed
	  		Pattern unknownPattern = new Pattern(messages.getString("rss.unknown.source"));
	  		String unknownMessage = unknownPattern.evaluate("source", sourceName);
	  		sendSpeech(tts.process(new Text("cs", unknownMessage), null));
	  	} else {
	  		InputStreamReader in = null;
	  		try {
	        URL feedUrl = new URL(config.getAddress());
	        SyndFeedInput feedInput = new SyndFeedInput();
	        in = new InputStreamReader(feedUrl.openStream(), config.getEncoding());
	        SyndFeed feed = feedInput.build(in);
	        feed.setEncoding(config.getEncoding());
	        String language = feed.getLanguage();
	        log.info(String.format("language=%s", language));
	        @SuppressWarnings("unchecked")
          List<SyndEntry> entries = feed.getEntries();
	        StringBuilder news = new StringBuilder();
	        int found = 0;
	        for (SyndEntry entry : entries) {
	        	String title = entry.getTitle();
	        	if (title != null)
	        		news.append(title + ".....\n");
	        	found++;
	        	if (found >= maxMessageCount)
	        		break;
	        }
	        Pattern foundPattern = new Pattern(LanguageDescription.EMPTY, messages.getString("rss.messages.found"));
	        String foundMessage = foundPattern.evaluate("count", Integer.toString(found));
	        news.insert(0, foundMessage + ".....");
	        log.debug("found message generated: " + foundMessage);
	        sendSpeech(tts.process(new Text(language, news.toString()), null));
        } catch (MalformedURLException e) {
	        log.warn("A MalformedRequestException occurred", e);
        } catch (IllegalArgumentException e) {
	        log.error("An IllegalArgumentException occurred", e);
        } catch (FeedException e) {
	        log.error("A FeedException occurred");
        } catch (UnsupportedEncodingException e) {
	        log.error("An UnsupportedEncodingException occurred", e);
        } catch (IOException e) {
	        log.error("An IOException occurred", e);
        } finally {
        	if (in != null) {
	          try {
	            in.close();
            } catch (IOException e) {
    	        log.error("An IOException occurred", e);
            }
        	}
        }
	  	}
	  }
  }

	private void sendSpeech(Speech speech) {
		for (NabaztagProxy proxy : nab.getRegisteredBunnies())
			proxy.playSound(speech);
	}

	public final static class FeedConfiguration {

		public FeedConfiguration(String address) {
			address.getClass();
			this.address = address;
		}

		private final String address;

		public String getAddress() {
			return address;
		}

		private final static String DEFAULT_ENCODING = "UTF8";
		private String encoding = DEFAULT_ENCODING;

		public String getEncoding() {
			return encoding;
		}

		public void setEncoding(String encoding) {
			if (encoding == null || encoding.equals(""))
				this.encoding = DEFAULT_ENCODING;
			else
				this.encoding = encoding;
		}
	}

}
